using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;

namespace AwesomeCMSCore.Modules.Background.BaseBackground
{
	public abstract class HostedService : IHostedService
	{
		// Example untested base class code kindly provided by David Fowler: https://gist.github.com/davidfowl/a7dd5064d9dcf35b6eae1a7953d615e3

		private Task _executingTask;
		private CancellationTokenSource _cts;

		public Task StartAsync(CancellationToken cancellationToken)
		{
			// Create a linked token so we can trigger cancellation outside of this token's cancellation
			_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

			// Store the task we're executing
			_executingTask = ExecuteAsync(_cts.Token);

			// If the task is completed then return it, otherwise it's running
			return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask;
		}

		public async Task StopAsync(CancellationToken cancellationToken)
		{
			// Stop called without start
			if (_executingTask == null)
			{
				return;
			}

			// Signal cancellation to the executing method
			_cts.Cancel();

			// Wait until the task completes or the stop token triggers
			await Task.WhenAny(_executingTask, Task.Delay(-1, cancellationToken));

			// Throw if cancellation triggered
			cancellationToken.ThrowIfCancellationRequested();
		}

		// Derived classes should override this and execute a long running method until 
		// cancellation is requested
		protected virtual async Task ExecuteAsync(CancellationToken stoppingToken)
		{
			do
			{
				await ProcessBackgroundTask();

				await Task.Delay(5000, stoppingToken);
			} while (!stoppingToken.IsCancellationRequested);
		}

		protected abstract Task ProcessBackgroundTask();
	}
}
